'''
* This file is part of the Chinchon (https://notabug.org/alkeon/chinchon.
* Copyright (c) 2020 Alejandro "alkeon" Castilla.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
'''

from hand import Hand
from copy import deepcopy

debug = False

'''
Checks if string can be converted to int
'''
def possible_int(string):
    try: 
        int(string)
        return True
    except ValueError:
        return False

class Player:

    def __init__(self, hand, mode, hard_mode):
        self.mode = mode
        self.hand = hand
        self.possible_end = 0
        self.hard_mode = hard_mode
        self.deck_cards_avoided = 0
    
    
    '''
    Easy mode AI
    Takes risk when choose card from deck.
    Try best movement but never tries a chinchon or a full hand unless luck give it
	'''
    def decide_next_move_easy(self, card):
        initial_points = self.hand.calculate_points()
        choice_and_position = list() 

        if(initial_points >= 4):
            best_move_list = self.best_move(card, initial_points)
        
            if(best_move_list[1] < initial_points):
                choice_and_position.append(1)
                choice_and_position += best_move_list
            else: 
                choice_and_position.append(0)
                choice_and_position.append(best_move_list[0])
                choice_and_position.append(best_move_list[1] + 10)
        
        else:
            choice_and_position.append(2)
            choice_and_position.append(0)
            choice_and_position.append(initial_points)
        return choice_and_position

    '''
    Hard mode AI
    Knows first card from deck
    Try best movement but never tries a chinchon or a full hand unless luck give it
	'''
    def decide_next_move_hard(self, card, deck_card): 
        initial_points = self.hand.calculate_points()
        choice_and_position = list() #result

        if(initial_points >= 4):
            best_move_list = self.best_move(card, initial_points)
            best_move_list_deck_card = self.best_move(deck_card, initial_points)
            if(best_move_list[1] < best_move_list_deck_card[1] and
               best_move_list[1] < initial_points):
               
                choice_and_position.append(1)
                choice_and_position += best_move_list

            elif(best_move_list[1] > best_move_list_deck_card[1] and
                best_move_list_deck_card[1] < initial_points):

                choice_and_position.append(0)
                choice_and_position += best_move_list_deck_card

            elif(self.deck_cards_avoided < 10):
                choice_and_position.append(1)
                choice_and_position += best_move_list
                self.deck_cards_avoided += 1

            else:
                choice_and_position.append(0)
                choice_and_position += best_move_list_deck_card
                self.deck_cards_avoided = 0

        elif(self.possible_end <= 5):
            best_move_list = self.best_move(card, initial_points)
            choice_and_position.append(1)
            choice_and_position += best_move_list
            self.possible_end += 1
        else:
            choice_and_position.append(2)
            choice_and_position.append(0)
            choice_and_position.append(initial_points)
        return choice_and_position
    '''
    Greedy algorithm that checks all movements points
    '''
    def best_move(self, card, initial_points):
        temporal_hand = deepcopy(self.hand)
        temporal_hand.insert(0, card)
        position = 0
        min_points_position = 0
        min_points = initial_points
        while(position < len(temporal_hand.get_cards())):
            possible_hand = deepcopy(temporal_hand)
            possible_hand.pop(position)
            points = possible_hand.calculate_points()
            if(points < min_points):
                min_points_position = position
                min_points = points
            
            position += 1
        return_list = list()
        return_list.append(min_points_position)
        return_list.append(min_points)
        return return_list
    '''
    After AI choose best option, this code executes that option
    '''
    def opponent(self, deck, reversed_deck):
        choice_and_position = list()

        if(self.hard_mode == 1):
            choice_and_position = self.decide_next_move_hard(reversed_deck.get(0), deck.get(0))
        else:
            choice_and_position = self.decide_next_move_easy(reversed_deck.get(0))
        result = 0

        if(debug):

            print('choice')
            print(choice_and_position[0])
            print('position')
            print(choice_and_position[1])
            print('points')
            print(choice_and_position[2])

        if(choice_and_position[0] == 0):
            self.hand.insert(0, deck.get(0))
            deck.pop(0)
            reversed_deck.insert(0, self.hand.get(choice_and_position[1]))
            self.hand.pop(choice_and_position[1])

        elif(choice_and_position[0] == 1):
            self.hand.insert(0, reversed_deck.get(0))
            reversed_deck.pop(0)
            reversed_deck.insert(0, self.hand.get(choice_and_position[1]))
            self.hand.pop(choice_and_position[1])

        else:
            result = 2
        return result
    '''
    UI for choosing an option
    '''
    def choose_option(self, deck, reversed_deck):
        if(self.mode == 2):
            option_s = input('0 top of deck, 1 Reversed card , 2 stop ')
            choice = int()
            if(possible_int(option_s)):
                choice = int(option_s)
            else:
                choice = 0
            
            if(choice != 2):
                if(choice == 0):
                    self.hand.insert(0, deck.get(0))
                    deck.pop(0)
                else:
                    self.hand.insert(0, reversed_deck.get(0))
                    reversed_deck.pop(0)

                print(self.hand)
                card_position = int()
                card_position_s = input('Choose card by position ')
                if(possible_int(card_position_s)):
                    card_position = int(card_position_s)
                else:
                    card_position = 0
                reversed_deck.insert(0, self.hand.get(card_position))
                self.hand.pop(card_position)
            else:
                if(self.hand.calculate_points() > 3):
                    print('You must have less than four points in your hand')
                    choice = self.choose_option( reversed_deck, deck)
            return choice
        else:
            return self.opponent(deck, reversed_deck)

    def return_hand(self):
        return self.hand

    def set_hand(self,hand):
        self.hand = deepcopy(hand)

    def get_mode(self):
        return self.mode

    def get_hard_mode(self):
        return self.hard_mode

    def __str__(self):
        return str(self.hand)
